/*
 * Copyright 2011-2018 ijym-lee
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package me.ijleex.openapi.oauth.service.impl;

import java.util.ArrayList;
import java.util.List;
import javax.sql.DataSource;

import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import me.ijleex.openapi.oauth.entity.AccessUser;
import me.ijleex.openapi.oauth.entity.UserDetails;
import me.ijleex.openapi.oauth.service.UserService;

/**
 * 用户服务
 *
 * @author liym
 * @see org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
 * @see org.springframework.security.oauth2.provider.token.store.JdbcTokenStore
 * @since 2018-11-30 15:27 新建
 */
@Service("userService")
public class UserServiceImpl implements UserService {

    /**
     * 用户查询语句
     */
    private static final String USER_SELECT_SQL = "SELECT `id`,`user_no`,`password`,`name`,`email`,`tel_no`,`addr`,`url`,`public_key`,`private_key`,`remark`,`status`,`creator`,`create_time`,`modifier`,`modified_time` FROM t_api_access_user WHERE user_no=?";
    /**
     * 用户权限查询语句
     */
    private static final String USER_AUTH_SELECT_SQL = "SELECT authority FROM t_api_user_authority WHERE user_no=?";

    private final JdbcTemplate jdbcTemplate;

    public UserServiceImpl(DataSource dataSource) {
        Assert.notNull(dataSource, "DataSource required");
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    /**
     * {@inheritDoc}
     *
     * @see org.springframework.security.oauth2.provider.token.store.JdbcTokenStore#readRefreshToken(java.lang.String)
     * @see org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider#authenticate
     */
    @Override
    public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
        RowMapper<AccessUser> rowMapper = new BeanPropertyRowMapper<>(AccessUser.class);
        List<AccessUser> userList = this.jdbcTemplate.query(USER_SELECT_SQL, rowMapper, username);

        AccessUser user = null;
        if (!userList.isEmpty()) {
            user = userList.get(0);
        }

        if (user == null) {
            throw new UsernameNotFoundException("用户不存在：" + username);
        } else {
            List<String> roleList = this.jdbcTemplate.queryForList(USER_AUTH_SELECT_SQL,
                    new Object[]{username}, String.class);
            if (roleList.isEmpty()) {
                return new UserDetails(user);
            } else {
                List<SimpleGrantedAuthority> authorities = buildAuthorities(roleList);
                return new UserDetails(user, authorities);
            }
        }
    }

    /**
     * 权限转化
     *
     * <p>如 "USER,ADMIN" -> SimpleGrantedAuthority("USER") + SimpleGrantedAuthority("ADMIN")</p>
     *
     * @param roleList 权限列表
     */
    private List<SimpleGrantedAuthority> buildAuthorities(List<String> roleList) {
        List<SimpleGrantedAuthority> authorities = new ArrayList<>(roleList.size());
        for (String role : roleList) {
            authorities.add(new SimpleGrantedAuthority(role));
        }
        return authorities;
    }

}
